/*
 * $Id$
 *
 * Copyright (C) IUT Montreuil-University Paris 8, 2009-2010
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation; either version 2.1 of the License, or
 * (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.
 * 
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
 */

package fr.univ_paris8.iut.linc.align;


import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.net.URI;
import java.net.URISyntaxException;


import java.util.Properties;


import org.semanticweb.owl.align.AlignmentException;
import org.semanticweb.owl.align.AlignmentVisitor;
import org.semanticweb.owl.align.Cell;

import org.semanticweb.owlapi.apibinding.OWLManager;
import org.semanticweb.owlapi.model.*;
import org.semanticweb.owlapi.reasoner.OWLReasonerException;

import uk.ac.manchester.cs.owl.owlapi.OWLDataFactoryImpl;



import fr.inrialpes.exmo.align.impl.BasicParameters;
import fr.inrialpes.exmo.align.impl.edoal.EDOALAlignment;
import fr.inrialpes.exmo.align.impl.renderer.RDFRendererVisitor;
import fr.inrialpes.exmo.iddl.IDDLReasoner;
import fr.inrialpes.exmo.iddl.conf.Semantics;
import fr.inrialpes.exmo.ontowrap.BasicOntology;
import fr.inrialpes.exmo.ontowrap.Ontology;

import gnu.getopt.Getopt;
import gnu.getopt.LongOpt;


public class ComplexAlignment {
	
	
	/**
     * La méthode qui permet de déterminer les similarités entre les noeuds est par défaut SimSubStringDistance
     */
	public static String MethodSim="SimSubStringDistance";
	/**
     * Le seuil par défaut utilisé dans le calcul des similarités terminologique est 0.7
     */
	public static double thresholdSim=.7;		
	/**
	 * complexAlignment est l'alignement complexe final qui sera composé de correspondances formule à formule 
	 * et de correspondances concept simple à formule
	 */
	public static EDOALAlignment complexAlignment;
		
	public static String wndict;
	
	
	
	public static void main(String[] args) throws AlignmentException, URISyntaxException, OWLReasonerException, IOException {
		
		/**
	     * @param args the command line arguments
	     */
		
		try {
            URI uri1=null;
            URI uri2=null;
        	OWLOntologyManager man = OWLManager.createOWLOntologyManager();
        	EDOALAlignment resultat = new EDOALAlignment();
        	int nbsimpl =0;
        	int nbcomplexFF = 0, nbcomplexCF1 = 0, nbcomplexCF2 = 0;
                               
        	if (args.length >= 2) {
    			
        		uri1 = new URI( args[0] );		
        		uri2 = new URI( args[1] );
        		IRI documentIRI1 = IRI.create(args[0]);
                OWLOntology O1 = man.loadOntologyFromOntologyDocument(documentIRI1);
                IRI documentIRI2 = IRI.create(args[1]);
                OWLOntology O2 = man.loadOntologyFromOntologyDocument(documentIRI2); 
                Properties params = readParameters( args );
                
                Ontology o1 = new BasicOntology();
                Ontology o2 = new BasicOntology();
                                	            	
            	o1.setURI(uri1);
            	o2.setURI(uri2);
               
                /**
                 * Enrichir les deux ontologies
                 */
            	//O1= Enrich (man, O1, uri1);
                //O2= Enrich (man, O2, uri2);
                             
            	/**
                 * Générer l'alignement simlpe
                 */
            	SimpleAlignment sa = new SimpleAlignment();                
            	nbsimpl=sa.Align(uri1, uri2,o1,o2, (String) params.getProperty("output"),(String) params.getProperty("wndict")) ;
                
                /**
                 * Transformer les deux ontologies sous forme de graphes
                 */
                TransformOWLIntoGraph tr1 = new TransformOWLIntoGraph();
                TransformOWLIntoGraph tr2 = new TransformOWLIntoGraph();
                Graph gh1 = tr1.OWL_Graph(O1);
                Graph gh2 = tr2.OWL_Graph(O2);
                                
                /**
                 * Générer les correspondances complexes
                 */
                DetectionComplexCorrespondences dt = new DetectionComplexCorrespondences();
                complexAlignment = new EDOALAlignment();
            	complexAlignment.init(o1, o2);
                nbcomplexFF = dt.ComplexCorrespondencesFF(gh1, gh2, o1,o2); 
                //La méthode de détection de correspondances entre concept simple et formule est asymétrique
                //Il s'agit dont de lancer l'exécution deux fois en permutant l'ordre des ontologies à aligner
                nbcomplexCF1 = dt.ComplexCorrespondencesCF(gh1, gh2, 1);
                nbcomplexCF2 = dt.ComplexCorrespondencesCF(gh2, gh1, 2);
                   
                /**
                 * Stocker l'ensemble des correspondances simples et complexes dans un fichier
                 */
                resultat.init(o1, o2);
                resultat = sa.AddAlignment(sa.SimpAlignment, complexAlignment);               
                FileWriter rdfF = new FileWriter(new File( (String) params.getProperty("output") ));
        	    AlignmentVisitor rdfV = new RDFRendererVisitor(  new PrintWriter ( rdfF )  );
        	    resultat.render(rdfV);
        	    rdfF.flush();
        	    rdfF.close();
        	    
        	    System.out.println("L'ensemble des correspondances est stockés dans "+ (String) params.getProperty("output"));
        	    System.out.println (nbcomplexFF+ nbcomplexCF1 + nbcomplexCF2 + nbsimpl +" correspondances détectées" );
        	    System.out.println (nbsimpl +" correspondances simples");
        	    System.out.println (nbcomplexFF +" correspondances complexes entre deux formules");
                System.out.println (nbcomplexCF1 + nbcomplexCF2 +" correspondances complexes entre un concept simple et une formule");
                
                                              	    
                } else {
        		System.err.println("Need two arguments to proceed");
        		return ;
        	    }        
            
        }
            
         catch (OWLOntologyCreationException e) {
            System.out.println("Could not load ontology: " + e.getMessage());
        }
	}

	
	/**
     * Enrichir une ontologie en ajoutant de nouvelles relations de subsomption
     */
	public static OWLOntology Enrich (OWLOntologyManager man, OWLOntology O, URI uri) throws OWLReasonerException{
		
		IDDLReasoner reasoner = new IDDLReasoner();
        reasoner.addOntology(uri);  
        reasoner.setSemantics(Semantics.DL);
            	
        for (OWLClass cls1 : O.getClassesInSignature()) 
        	 for (OWLClass cls2 : O.getClassesInSignature()) 
        	 {
        		 if (!cls1.equals(cls2)){
        		 OWLDataFactoryImpl facto = new OWLDataFactoryImpl();
        		 OWLSubClassOfAxiom ax = facto.getOWLSubClassOfAxiom( cls1, cls2 );
        		 if (!O.containsAxiom(ax)){
        		 if (reasoner.isEntailed( ax ))
        			 {
        			 	AddAxiom addAx = new AddAxiom(O, ax);
        	            man.applyChange(addAx);
        			 }
        		 }
        		 }
        		
        	 }
        
        
       return O;
		
	}
	
	
	 /**
     * Lire les paramètres saisis par l'utilisateur
     */
	public static Properties readParameters( String[] args ) {
		Properties params = new BasicParameters();
		
		
		// Read parameters
		LongOpt[] longopts = new LongOpt[4];
		
		longopts[0] = new LongOpt("output", LongOpt.REQUIRED_ARGUMENT, null, 'o');
		longopts[1] = new LongOpt("wndict", LongOpt.REQUIRED_ARGUMENT, null, 'w');
		longopts[2] = new LongOpt("sim", LongOpt.OPTIONAL_ARGUMENT, null, 'm');
		longopts[3] = new LongOpt("thresholdSim", LongOpt.OPTIONAL_ARGUMENT, null, 't');
		Getopt g = new Getopt("", args, "o:w:m:t:", longopts);
		
		int c;
		String arg;
		
		
		
		while ((c = g.getopt()) != -1) {
		    switch (c) {
		    case 'o':
		    	arg = g.getOptarg();
		    	   	if ( arg != null ) {
		    	   		params.setProperty( "output", arg );
				    
				} 
		    	else {
				    System.err.println("Bad parameter syntax: "+g);
				    System.exit(0);
		    	}
		    	break;
		    	
		    case 'w' :
		    	
		    	arg = g.getOptarg();
		    	  	if ( arg != null ) {
				    params.setProperty( "wndict", arg );
				    
				} 
		    	else {
				    System.err.println("Bad parameter syntax: "+g);
				    System.exit(0);
		    	}
		    	break;
		    
		    case 'm' :
		    	
		    	MethodSim = g.getOptarg();
		    	
		    	
			break;
		    case 't' :
		    	
		    	thresholdSim = Double.parseDouble(g.getOptarg());
		    	   	
			break;
		    }
		}
		return params;
	}
	


}
